#ifndef _BUOLA_CV_IO_CWEBCAMDEVICE_H_
#define _BUOLA_CV_IO_CWEBCAMDEVICE_H_

#include <buola/buola.h>
#include <buola/threads/thread.h>
#include <buola/threads/condition_variable.h>
#include <buola/utility/usignal.h>
#include <buola/image/format.h>
#include <buola/io/curi.h>

#include <atomic>

namespace buola { namespace cvi {

class CWebCamDevice
{
    struct SFormat
    {
        uint32_t mPixel;
        CSize_i mSize;
        bool mInterlaced;
        size_t mStride; //in bytes
        size_t mTotalBytes;
    };
    
public:
    CWebCamDevice(const io::CURI &pDevice);
    ~CWebCamDevice();
    
    void Start();
    void Stop();
    
    img::CImage_rgb8 GetOne();

    USignal<void(const img::CImage_rgb8&)> sImage;
    
private:
    void Initialize();

    void OnThread();
    
    void DoStart();
    void DoStop();
    void DoIteration(int pCount);

    void IOCtl(long int pRequest,void *pPtr);
    bool IOCtl(std::nothrow_t,long int pRequest,void *pPtr);
    
    template<typename tType>
    tType IOCtl(long int pRequest)
    {
        tType lValue;
        memset(&lValue,0,sizeof(tType));
        IOCtl(pRequest,&lValue);
        return lValue;
    }
    
    std::vector<uint32_t> EnumerateFormats(uint32_t pType);
    SFormat QueryFormat(uint32_t pType);
    void ResetCrop(uint32_t pType);
    void SetIOMode(uint32_t pType);
    void EnqueueBuffer(uint32_t pType,char *pBuffer,int pIndex);
    
private:
    std::atomic<bool> mInitialized;
    io::CURI mDevice;
    int mFD;
    
    thread mThread;
    mutex mMutex;
    condition_variable mCondVar;

    int mSyncIndex;
    mutex mSyncMutex;
    condition_variable mSyncCondVar;
    img::CImage_rgb8 mSyncImage;
    
    std::atomic<int> mStartCount;    
    
    bool mStarted;
    
    SFormat mCurrentFormat;
};

/*namespace cvi*/ } /*namespace buola*/ }

#endif
